import time
import os
from datetime import datetime
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from minio import Minio
from minio.error import S3Error
from jsonconfig import Config
from logconfig import logger

# 加载配置
config = Config()
minio_config = config.get_minio_config()
# 修改为支持多个监控路径
watch_paths = config.get_watch_paths()  # 返回路径列表
file_monitor_config = config.get_file_monitor_config()

# 初始化 MinIO 客户端
minio_client = Minio(
    minio_config.get("endpoint", "8.137.58.206:9000"),
    access_key=minio_config.get("access_key", "9eBv4Rt6"),
    secret_key=minio_config.get("secret_key", "3a7W5Mz8"),
    secure=minio_config.get("secure", False)
)


class ImageUploadHandler(FileSystemEventHandler):
    def __init__(self):
        self.retry_queue = []
        self.extensions = file_monitor_config.get("extensions", [".jpg", ".png", ".jpeg", ".bmp"])
        self.stable_check_interval = file_monitor_config.get("stable_check_interval", 1)
        self.max_stable_wait = file_monitor_config.get("max_stable_wait", 10)
        self.max_retries = file_monitor_config.get("max_retries", 3)
        self.bucket_name = minio_config.get("bucket_name", "bucket1")

        # 确保MinIO桶存在
        self.ensure_bucket_exists(self.bucket_name)
        logger.info("初始化监控器")

    def ensure_bucket_exists(self, bucket_name):
        try:
            if not minio_client.bucket_exists(bucket_name):
                minio_client.make_bucket(bucket_name)
                logger.info(f"创建桶: {bucket_name}")
            else:
                logger.info(f"桶已存在: {bucket_name}")
        except S3Error as err:
            logger.error(f"检查桶失败: {err}")

    def wait_for_file_stable(self, file_path):
        """等待文件大小稳定"""
        size = -1
        wait_time = 0
        while wait_time < self.max_stable_wait:
            try:
                current_size = os.path.getsize(file_path)
            except OSError:
                current_size = -1
            if current_size == size:
                return True
            size = current_size
            time.sleep(self.stable_check_interval)
            wait_time += self.stable_check_interval
        return False

    def on_created(self, event):
        file_path = event.src_path
        if not event.is_directory and any(file_path.lower().endswith(ext) for ext in self.extensions):
            logger.info(f"检测到新文件: {file_path}")
            # 等待文件完全写入
            if self.wait_for_file_stable(file_path):
                self.upload_file(file_path)
            else:
                logger.warning(f"文件未稳定，放弃上传: {file_path}")

    def upload_file(self, file_path):
        for attempt in range(self.max_retries):
            timestamp = str(int(time.time()))
            # 保留原始文件扩展名
            original_ext = os.path.splitext(file_path)[1].lower()
            original_filename = os.path.basename(file_path)   # 原图名字
            # 根据文件路径生成对象名，包含文件夹信息
            folder_name = os.path.basename(os.path.dirname(file_path))
            # object_name = f"{folder_name}/{timestamp}{original_ext}"
            object_name = f"{folder_name}/{original_filename}"
            try:
                minio_client.fput_object(
                    self.bucket_name,
                    object_name,
                    file_path,
                )
                logger.info(f"图片 {file_path} 已成功上传为对象 {object_name}")
                os.remove(file_path)  # 删除本地文件
                return True
            except S3Error as err:
                logger.error(f"MinIO上传失败（尝试 {attempt + 1}/{self.max_retries}）: {err}")
            except Exception as e:
                logger.error(f"上传异常（尝试 {attempt + 1}/{self.max_retries}）: {e}")
            # time.sleep(2 ** attempt)  # 指数退避
            time.sleep(2 * attempt)  # 线性退避

        logger.error(f"放弃上传，保留文件: {file_path}")
        return False

def ensure_directory_exists(directory_path):
    """确保目录存在，如果不存在则创建"""
    if not os.path.exists(directory_path):
        try:
            os.makedirs(directory_path, exist_ok=True)
            logger.info(f"创建目录: {directory_path}")
            return True
        except Exception as e:
            logger.error(f"创建目录失败 {directory_path}: {e}")
            return False
    else:
        logger.debug(f"目录已存在: {directory_path}")
        return True

def start_monitoring():
    """开始监控多个目录"""
    observer = Observer()
    event_handler = ImageUploadHandler()

    # 确保所有监控路径都存在
    valid_watch_paths = []
    for watch_path in watch_paths:
        if ensure_directory_exists(watch_path):
            valid_watch_paths.append(watch_path)
        else:
            logger.error(f"无法创建监控路径，跳过: {watch_path}")

    # 监控所有有效路径
    for watch_path in valid_watch_paths:
        observer.schedule(event_handler, watch_path, recursive=False)
        logger.info(f"开始监控目录: {watch_path}")

    if not valid_watch_paths:
        logger.error("没有有效的监控路径，程序退出")
        return

    observer.start()
    logger.info(f"总共监控 {len(watch_paths)} 个目录")

    try:
        while True:
            time.sleep(1)
    except KeyboardInterrupt:
        observer.stop()
        logger.info("监控已停止")
    observer.join()


# 使用示例
if __name__ == "__main__":
    start_monitoring()